#include "testApp.h"
#define ARDUINO_BAUD_RATE 9600

TestApp::TestApp()
{
	flash = 0;
}


void TestApp::loadStartupData()
{
	ofFile f;
	if (f.open("StartupData.txt")) {
		ofBuffer buf = f.readToBuffer();
		
		while (!buf.isLastLine()) {
			string line = buf.getNextLine();
			string line2 = buf.getNextLine();
			
			string msg = line.substr(0,line.length()-1)+line2;
//			printf("msg: %s\n", msg.c_str());

			for (int i=0;i<10;i++)
				parseFlashMsg(msg);
			return;
		}
	}
}


void TestApp::addFixedCircle(ofVec2f pos)
{
	ofxBox2dCircle* c = new ofxBox2dCircle();
	c->setup(box2d.getWorld(), pos.x, pos.y, 5);
	c->setDensity(0);
	fixedCircles.push_back(c);
}

void TestApp::initLinkObjects()
{
	// Create all the fixed-position elements in the game that represent links to webpages

	float mx = ofGetWindowWidth()/2;
	float my = ofGetWindowHeight()/2;

	struct LinkObjectDef {
		ofVec2f pos;
		const char *texture;
	} pts[] = {
		{ ofVec2f(-0.5f, -0.5f), "facebook" } ,
		{ ofVec2f(0.0f, -0.5f), "flickr" },
		{ ofVec2f(0.5f, -0.5f), "twitter" },

		{ ofVec2f(0.0f, 0.0f), "youtube" },
		{ ofVec2f(0.3f, 0.5f), "nu_nl" },
		{ ofVec2f(-0.3f, 0.5f), "google" }
	};
	int n = 6;

	for (int i=0;i<n;i++) {
		auto p = pts[i];
		LinkObject *lo = new LinkObject();

		std::string filename = std::string(p.texture) + ".jpg";
		if (lo->image.loadImage(filename)) {
			ofLog(OF_LOG_NOTICE, "Loaded " + filename);
			linkObjects.push_back(lo);

			float h=50;
			float w=h*lo->image.width/lo->image.height;
			
			ofVec2f pos=ofVec2f(mx,my)*(ofVec2f(1,1)+p.pos);

			lo->rect.setup(box2d.getWorld(), pos.x-w/2,pos.y-h/2,w,h);
			lo->rect.setPhysics(0.0f, 0.8f, 0.2f);
			lo->rect.body->SetUserData(lo);
			lo->url = p.texture;
		} else delete lo;
	}
}

void TestApp::drawLinkObjects()
{
	for (int i=0;i<linkObjects.size();i++) {
//		ofFill();
		ofSetHexColor(0xff0000);
		//linkObjects[i]->circle.draw();
				
		auto lo = linkObjects[i];
		if (lo->image.width>0) {
			ofVec2f p = lo->rect.getPosition();
			float w= lo->rect.getWidth();
			float h= lo->rect.getHeight();

			ofRectangle rc (p.x-w/2,p.y-h/2,w,h);
			ofRectangle outer = rc;
			outer.scaleFromCenter(1.2f);

			ofFill();
			ofColor(255,255,255);
			ofRectRounded(outer, 4);
			ofNoFill();
			ofColor(0,0,0);
			ofRectRounded(outer, 4);

			ofSetHexColor(0xffffff);
			lo->image.draw(rc.x,rc.y,rc.width,rc.height);
		}
	}
}

// Returns the object with type1
GameObject* combinationOf(GameObject* a, GameObject* b, GameObject::ObjectType type1, GameObject::ObjectType type2)
{
	bool r = (a->objType == type1 && b->objType == type2 ) || (a->objType == type2 && b->objType == type1 );
	
	if (r) {
		return (a->objType == type1) ? a : b;
	}
	return 0;
}


void TestApp::BeginContact(b2Contact* c)
{
	b2Body* a = c->GetFixtureA()->GetBody();
	b2Body* b = c->GetFixtureB()->GetBody();

	if (a && a->GetUserData() && b && b->GetUserData()) {
	
		GameObject* goA = (GameObject*)a->GetUserData();
		GameObject* goB = (GameObject*)b->GetUserData();
		GameObject* playerHitLink = combinationOf(goA, goB, GameObject::Link, GameObject::Player);
		
		if (playerHitLink) {
			messages.push_back("player hit link: " + ((LinkObject*)playerHitLink)->url);
//			oscSender.sendMessage();
		}
		
		GameObject* playerHitBullet = combinationOf(goA, goB, GameObject::Bullet, GameObject::Player);
		if (playerHitBullet) {
			
		}
	}
}

void TestApp::EndContact(b2Contact* c)
{
}

void TestApp::exit() {

	#ifdef FLASHCOMM
	delete flash;
	#endif

	DeleteAllElems(staticPoly);
	DeleteAllElems(staticGeom);
	DeleteAllElems(linkObjects);
	DeleteAllElems(bullets);
	DeleteAllElems(outsideBullets);
	DeleteAllElems(fixedCircles);
}


//--------------------------------------------------------------
void TestApp::setup() {

	drawFixedCircles = true;

	//oscReceiver.setup(3333);
#ifdef FLASHCOMM
	flash = new ofxFlashCommunication();
    flash->setup("127.0.0.1",1234);
	flash->addPolicy("*","*");
	flash->start();
#endif
	ofSetVerticalSync(true);
	ofBackgroundHex(0xffffff);
	ofSetLogLevel(OF_LOG_NOTICE);
	
	box2d.init();
	box2d.setGravity(0, 0);
	box2d.setFPS(60);
	box2d.createBounds();
	box2d.getWorld()->SetContactListener(this);

	// initialize all fixed items

	auto outerPts=computeBoundary(0);
	auto innerPts=computeBoundary(10);
	// generate quads to represent boundary
	b2BodyDef bdef;
	bdef.type = b2_staticBody;
	staticPolyBody = box2d.getWorld()->CreateBody(&bdef);
		
	for(int i=0;i<innerPts.size();i++){
		int j=(i+1)%innerPts.size();
		
		b2PolygonShape* ps = new b2PolygonShape();
		
		ofPoint verts[4];
		verts[0] = outerPts[i];
		verts[3] = outerPts[j];
		verts[2] = innerPts[j];
		verts[1] = innerPts[i];

		b2Vec2 pts2[4];
		for (int k=0;k<4;k++) {
			pts2[k]= b2Vec2(verts[k].x,verts[k].y);
			pts2[k]*=1.0f/OFX_BOX2D_SCALE;
		}
		ps->Set(pts2, 4);
		staticPoly.push_back(ps);
		b2FixtureDef f;
		f.density = 0;
		f.restitution = 1.0;
		f.friction = 1.0f;
		f.shape = ps;
		staticPolyBody->CreateFixture(&f);
	}

	float grayOuter=0.8f;
	float grayInner=0.4f;
	addGradientQuads(innerPts, outerPts, ofFloatColor(grayInner,grayInner,grayInner,1.0f), ofFloatColor(grayOuter,grayOuter,grayOuter,1.0f));

/*	grayInner=0;
	outerPts = innerPts;
	innerPts = computeBoundary(70);
	addGradientQuads(innerPts, outerPts, ofFloatColor(1,1,1,1), ofFloatColor(grayInner,grayInner,grayInner,1.0f));*/

	initLinkObjects();
	
	auto boundary = computeBoundary(-20);
	for(int i=0;i<boundary.size();i++)
		turretBoundaryLine.addVertex(boundary[i]);
	turretBoundaryLine.close();
	movingTurret = false;
	turretPosition = 0.0f;

	serialDevices = arduino.getDeviceList();
	selectedSerial = 0;
	arduinoEnabled = false;
	
	backgroundShader.load("shaders/background.vert", "shaders/background.frag");
	ofSetBackgroundAuto(true);
	//ofEnableAlphaBlending();
	  
//	bulletShape.setRadius(1);
//	bulletShape.enableNormals();
	
	player.setup(&box2d, ofVec2f(ofGetWindowWidth()/2 , ofGetWindowHeight()/2 ) );

	initFixedCircles();
	
	loadStartupData();
	
	ofRegisterURLNotification(this);
}

void TestApp::addGradientQuads(const vector<ofVec2f>& a,const vector<ofVec2f>& b, ofFloatColor colA, ofFloatColor colB)
{
	vector<ofFloatColor> colors;
	vector<ofVec3f> verts;
	
	for (int i=0;i<a.size();i++) {
		int j =(i+1)%a.size();

		verts.push_back(a[i]); colors.push_back(colA);
		verts.push_back(a[j]); colors.push_back(colA);
		verts.push_back(b[j]); colors.push_back(colB);
		verts.push_back(b[i]); colors.push_back(colB);
	}
	
	StaticMesh* mesh = new StaticMesh();
	ofVbo* vbo = &mesh->vbo;
	vbo->setVertexData(&verts[0], verts.size(), GL_STATIC_DRAW);
	vbo->setColorData(&colors[0], verts.size(), GL_STATIC_DRAW);
	vbo->enableColors();
	
	mesh->mode = GL_QUADS;
	mesh->numVerts = verts.size();
		
	staticGeom.push_back(mesh);
}


void TestApp::drawPolyline(ofPolyline& pl)
{
	ofBeginShape();
	float s=0.05f;
	vector<ofPoint>& vrt = pl.getVertices();
    for( int i = 0; i < vrt.size(); i++) {
		ofVec3f n =	pl.getNormalAtIndex(i);;
		glNormal3fv((float*)&n);
		glTexCoord2f(vrt[i].x*s, vrt[i].y*s);
        ofVertex(vrt[i].x, vrt[i].y);  
    }  
	ofEndShape();  
}

vector<ofVec2f> TestApp::computeBoundary(float Rofs)
{
	int N=30;
			// w=35,h=43,midsection=13
	float w=ofGetWidth();
	float margin=50+Rofs;
	float R=w*0.48-margin;
	float h=ofGetHeight();
	vector<ofVec2f> pts;

	// right corner
	for (int i=0;i<N;i++)
	{
		float ph=i*0.5f*3.141593f/N;
		pts.push_back( ofVec2f(w-margin-R+cos(ph)*R, margin+R-sin(ph)*R) );
	}

	// left corner
	for (int i=0;i<N;i++)
	{
		float ph=i*0.5f*3.141593f/N;
		pts.push_back(ofVec2f(R+margin-sin(ph)*R, margin+R-cos(ph)*R));
	}

	// bottom left
	for (int i=0;i<N;i++)
	{
		float ph=i*0.5f*3.141593f/N;
		pts.push_back(ofVec2f(R+margin-cos(ph)*R, h-margin-R+sin(ph)*R));
	}
	// bottom right
	for (int i=0;i<N;i++)
	{
		float ph=i*0.5f*3.141593f/N;
		pts.push_back(ofVec2f(w-R-margin+sin(ph)*R, h-margin-R+cos(ph)*R));
	}

	return pts;
}

void TestApp::showMessageString(const string &s)
{
	messages.push_back(s);
	if (messages.size() > 5)
		messages.pop_front();
}

void TestApp::parseFlashMsg(const string& msg) {

	if (!msg.empty()) {
		
		if (msg[0] == '$') {
			string x = msg.substr(1);
			string::size_type url_start = x.find('$');
			
			string keyword = x.substr(0, url_start);
			string url = x.substr(url_start+1);
			
			addOutsideBullet(url, keyword);
		}
	}
	else {
		showMessageString(msg);
	}
}

void TestApp::urlResponse(ofHttpResponse &httpResponse)
{
	int id = httpResponse.request.getID();
	ofLog(OF_LOG_NOTICE, "receiving response from request ID:" + ofToString(id) + ". URL: " + httpResponse.request.url);

	for(int i=0;i<outsideBullets.size();i++) {
		auto b = outsideBullets[i];
		if (b->asyncLoadID == id) {
			b->imageMutex.lock();
			b->image.loadImage(httpResponse.data);
			b->imageMutex.unlock();
		}
	}
}


void TestApp::addOutsideBullet(const string& url, const string& keyword)
{
	Bullet* b = new Bullet();
	b->imageURL = url;
	b->keyword = keyword;
	
	// find a random position along the field
	float randomPos = ofRandomuf();
	float len = turretBoundaryLine.getPerimeter();
	float index = turretBoundaryLine.getIndexAtLength(randomPos*len);
	ofVec2f pos = turretBoundaryLine.getPointAtIndexInterpolated(index);
	ofVec2f normal = turretBoundaryLine.getNormalAtIndexInterpolated(index);
	
	ofVec2f vel =(ofVec2f(ofRandomf(), ofRandomf())).rescale(5);
	b->setup(&box2d, pos+normal*20, vel);
	
	if (!url.empty()) {
		b->asyncLoadID = ofLoadURLAsync(url);
		ofLog(OF_LOG_NOTICE, "loading " + url + ". Request ID: " + ofToString(b->asyncLoadID));
	}

	outsideBullets.push_back(b);
	showMessageString("add bullet: Keyword: " + keyword);
}



void TestApp::fireBullet()
{
	// find the closest bullet to shoot
	ofVec2f turretNorm;
	ofVec2f turretPos = computeTurretPosition(&turretNorm);
	Bullet* closest = 0;
	float closestDist = 0;
	for (int i=0;i<outsideBullets.size();i++) {
		float dist = (outsideBullets[i]->getPosition() - turretPos).length();
		if (!closest || dist < closestDist) {
			closest = outsideBullets[i];
			closestDist = dist;
		}
	}
	
	// transition
	if (closest) {
		// remove it from the outside bullet list
		outsideBullets.erase(find ( outsideBullets.begin(), outsideBullets.end(), closest ));

		Bullet *b = closest;
		b->state = Bullet::BeingFired;
		SetBodyCollision(b->shape.body, COL_BULLET, 0);
		
		ofVec2f firePos = computeBulletFirePosition();
		ofVec2f impulse = ( firePos - b->getPosition() ) * 20 / OFX_BOX2D_SCALE;
		b->shape.body->ApplyLinearImpulse(b2Vec2(impulse.x,impulse.y), b->shape.body->GetPosition());

		bullets.push_back(b);
	}
}

void TestApp::drawBullet(Bullet* b)
{
	ofFill();
	ofSetColor(255,255,255);

	ofPushMatrix();
	
	ofTranslate(b->shape.getPosition());
	ofRotate(b->shape.getRotation());
	
	ofRectangle rc(-20,-20,40,40);
	if (b->image.isAllocated())
		b->image.draw(rc);
	else
		ofRect(rc);
	
	ofPopMatrix();
}


ofVec2f TestApp::computeBulletFirePosition()
{
	ofVec2f turretNorm;
	ofVec2f turretPos = computeTurretPosition(&turretNorm);
	ofVec2f dir = (player.getPosition()-turretPos);
	dir *= 30.0f/(dir.length()+0.01f);
	return turretPos+turretNorm*80;
}

void TestApp::updateBullets() {
	
	ofVec2f turretDir, bulletFirePos = computeBulletFirePosition();
	ofVec2f turretPos = computeTurretPosition(&turretDir);
	
	float time = ofGetElapsedTimef();

	vector<Bullet*> newBullets;
	for (int i=0;i<bullets.size();i++) {
		Bullet* b = bullets[i];
		
		if (b->state == Bullet::BeingFired) {
			b2Body* body = b->shape.body;
			ofVec2f f = 20 * (bulletFirePos - b->getPosition()) / OFX_BOX2D_SCALE;
			body->ApplyForce(b2Vec2(f.x,f.y), body->GetPosition());

			if ( (b->getPosition() - bulletFirePos).length() < 30 )
			{
				SetBodyCollision(b->shape.body, COL_BULLET, COL_ALL);

				b->state = Bullet::Inside;
				ofVec2f impulse(turretDir * 60 / OFX_BOX2D_SCALE), impulsePt (bulletFirePos);
				//body->SetLinearVelocity(b2Vec2());
				body->SetTransform( b2Vec2(bulletFirePos.x / OFX_BOX2D_SCALE, bulletFirePos.y / OFX_BOX2D_SCALE), body->GetAngle());
				body->ApplyLinearImpulse(b2Vec2(impulse.x,impulse.y), b2Vec2(impulsePt.x,impulsePt.y));
				b->startTime = time;
			}
		}
		
		if (b->state == Bullet::Inside) {
			if (time - b->startTime > 5) {
				b->state = Bullet::Disappearing;
				b->startTime = time;
			}
		}

		if (b->state == Bullet::Disappearing && time - b->startTime > 1)
			delete b;
		else
			newBullets.push_back(b);
	}
	
	bullets = newBullets;
}

void TestApp::update() {

	if (ofGetMousePressed(0)) {
		int dx = mouseX-ofGetWindowWidth()/2;
		
		turretPosition -= dx*0.005f/ofGetWindowWidth();
		turretPosition = turretPosition-floor(turretPosition);
	}

#ifdef FLASHCOMM
    while(flash->hasMessage()) {
		string message = flash->getNextMessage();
        parseFlashMsg(message);
//		cout << "received: '" << message << "'" << endl;
		puts( (message + "\n").c_str());
		ofLog(OF_LOG_NOTICE, "flashmsg: " + message );
	}
#endif
	ofxOscMessage msg;
	while (oscReceiver.getNextMessage(&msg)) {
		if(msg.getNumArgs()>0 &&  msg.getArgType(0) == OFXOSC_TYPE_STRING ) {
			parseFlashMsg(msg.getArgAsString(0));
		}
	}

	if (arduinoEnabled) {
		arduinoUpdate();
		
		turretPosition += controlSliderValue.x*0.0001f;
		turretPosition = turretPosition-floor(turretPosition);
	}

	updateBullets();
	
	box2d.update();
}

void TestApp::arduinoUpdate()
{
	while (arduino.available() > 0) {
		char v = (char)arduino.readByte();
		
		#if 0
		
		if(v == '\n') {
			if (buffer.size()>0 && buffer[0] == '#') {
			
				vector<string> r = ofSplitString(buffer, "\t");
				// position commands
//				ofLog(OF_LOG_NOTICE, "r.size() = " + ofToString(r.size()));
				if(r.size()>3) {
					controlSliderValue = ofVec2f( ofToInt(r[1]), ofToInt(r[2]) );
//					ofLog(OF_LOG_NOTICE, ofToString( controlSliderValue.x ) );
					uint32_t digin = ofToInt(r[3]);
				}
				buffer.clear();
			} else {
				showMessageString(buffer);
				buffer.clear();
			}
		} else
			buffer += v;
			
		#else
		if (v == ',') {
//			ofLog(OF_LOG_NOTICE, "buffer: " +buffer);
            if (buffer.substr(0,4) == "bOff") {
			} else if (buffer.substr(0,3) == "bOn") {
			
				fireBullet();
			} else {
                buffer=buffer.substr(1);
				controlSliderValue.x = ofToInt(buffer);
			}
			buffer.clear();
		} else {
			buffer += v;
        }
		#endif
	}
}

ofVec2f TestApp::computeTurretPosition(ofVec2f *normal)
{
	float len = turretBoundaryLine.getPerimeter();
	float index = turretBoundaryLine.getIndexAtLength(turretPosition*len);
	ofVec2f pos = turretBoundaryLine.getPointAtIndexInterpolated(index);
	if (normal) {
		*normal = turretBoundaryLine.getNormalAtIndexInterpolated(index);
	}
	return pos;
}

void TestApp::drawTurret()
{
	ofVec2f normal;
	ofVec2f pos = computeTurretPosition(&normal);
	
	ofFill();
	ofSetHexColor(0x00ff00);
	
	ofDrawSphere(pos.x,pos.y, 20);
}


//--------------------------------------------------------------


void TestApp::draw() {

	drawBackground();

	for (int i=0;i<staticGeom.size();i++)
		staticGeom[i]->vbo.draw(staticGeom[i]->mode, 0, staticGeom[i]->numVerts);
	
	setupLighting();
		
	drawLinkObjects();
	for (int i=0;i<bullets.size();i++)
		drawBullet(bullets[i]);
	for (int i=0;i<outsideBullets.size();i++)
		drawBullet(outsideBullets[i]);
		
	for (int i=0;i<fixedCircles.size();i++) {
		fixedCircles[i]->draw();
	}
	ofEnableLighting();
	drawTurret();
	player.draw();
	
	ofDisableLighting();

	string info = "";
	info += "Press [c] for circles, [k]: OSC msg to localhost \n";
	info += "Total Bodies: "+ofToString(box2d.getBodyCount())+"\n";
	info += "FPS: "+ofToString(ofGetFrameRate(), 1)+"\n";
	info += "Control input: X: " + ofToString(controlSliderValue.x, 0) + "; Y: " + ofToString(controlSliderValue.y,0) +"\n";
//	ofVec2f turPos = computeTurretPosition();
//	info += "Turret pos: " + ofToString(turretPosition, 2) + " X=" + ofToString(turPos.x) + " ,Y=" + ofToString(turPos.y) + "\n";
	
	if (!serialDevices.empty())
		info += "Selected serial port: "+serialDevices[selectedSerial].getDeviceName()+"\n";
	ofSetHexColor(0xff);
	ofDrawBitmapString(info, 30, 30);
   
    //shadows
	drawFixedColumnShadows();
    drawAimingLine();
		
	info = "";
	for (auto i = messages.begin(); i!=messages.end(); ++i)
		info += *i + "\n";
	ofDrawBitmapString(info, 30, 200);
}


void TestApp::drawFixedColumnShadows()
{
    float angle;
    float distance;
    float Length;
    ofVec2f playerPos = player.circle.getPosition();
    ofSetHexColor(0x202020);
    for(int i=0;i<fixedCircles.size();i++){
	
		ofVec2f pos = fixedCircles[i]->getPosition();
		ofVec2f dir = pos - playerPos;
		ofVec2f ortho = dir.perpendiculared();

		ofVec2f endPos = pos + dir * 0.2;
		float hw = 5;
		ofVec2f v1 = pos + ortho * hw;
		ofVec2f v2 = endPos + ortho * hw;
		ofVec2f v3 = endPos - ortho * hw;
		ofVec2f v4 = pos - ortho * hw;
		
		glBegin(GL_POLYGON);
		glVertex2fv((float*)&v1);
		glVertex2fv((float*)&v2);
		glVertex2fv((float*)&v3);
		glVertex2fv((float*)&v4);
		glEnd();

		ofCircle(endPos.x, endPos.y, hw);
	}
	
}

void TestApp::drawAimingLine()
{
    ofSetHexColor(0x202020);
    float hw = 15;
    ofVec2f turretNorm;
    ofVec2f turretPos = computeTurretPosition(&turretNorm);
    ofVec2f playerPos = player.circle.getPosition();
    ofVec2f dir = turretPos - playerPos;
    ofVec2f endPos=turretPos-dir*0.5;
    ofVec2f ortho = dir.perpendiculared();
    
    ofVec2f v1 = endPos;
    ofVec2f v2 = turretPos + ortho * hw;
    ofVec2f v3 = turretPos - ortho * hw;
    
    glBegin(GL_POLYGON);
    glVertex2fv((float*)&v1);
    glVertex2fv((float*)&v2);
    glVertex2fv((float*)&v3);
    glEnd();
}

//--------------------------------------------------------------
void TestApp::keyPressed(int key) {
			
	if (key == 'k') {
		oscSender.setup("127.0.0.1", 3333);
		ofxOscMessage msg;
		msg.addStringArg("testing...");
		oscSender.sendMessage(msg);
	}
	
	if (key == '[') {
		selectedSerial--;
		if (selectedSerial<0) selectedSerial = serialDevices.size()-1;
	}
	if (key == ']') {
		selectedSerial++;
		if (selectedSerial>=serialDevices.size()) selectedSerial=0;
	}
	if (key == 'a') {
		auto serial = serialDevices[selectedSerial];
		int portID = serial.getDeviceID();
		string devPath = serial.getDevicePath();
		string portName = serial.getDeviceName();
		arduinoEnabled = arduino.setup(devPath, ARDUINO_BAUD_RATE);
	}

	if (key == ' ') {
		fireBullet();
	}
	
	if (key == 'j') {
		string url="https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQs2Ya3GPHkNMWB0jHlBeeYPhadrxeQEFE7I7domkq-ZRPpUtOu";
		string keyword = "hyperloop";
		
		addOutsideBullet(url, keyword);
	}
	
	if (key == 'b') {
		addOutsideBullet("", "");
	}
	
	if (key == 'p') {
		addFixedCircle(ofVec2f(mouseX,mouseY));
		ofLog(OF_LOG_NOTICE, "fixed circle: X=" + ofToString(mouseX) + " , " + ofToString(mouseY));
	}
}

//--------------------------------------------------------------
void TestApp::keyReleased(int key) {
//	if (key == ')
}

//--------------------------------------------------------------
void TestApp::mouseMoved(int x, int y ) {
}

//--------------------------------------------------------------
void TestApp::mouseDragged(int x, int y, int button) {
}

//--------------------------------------------------------------
void TestApp::mousePressed(int x, int y, int button) {
	clickPos = ofVec2f(x,y);
#ifdef FLASHCOMM
	flash->send("this message is sent from openFrameworks");
#endif
}

//--------------------------------------------------------------
void TestApp::mouseReleased(int x, int y, int button) {
/*	ofVec2f pos(x,y);
	float dist = (clickPos-pos).length();
	if (dist > 10) {
		float r = 5;		// a random radius 4px - 20px
		ofxBox2dCircle circle;
		circle.setPhysics(3.0, 0.9, 0.05);
		circle.setup(box2d.getWorld(), pos, r);
		circle.setVelocity( (pos-clickPos) * 0.1f );
		circles.push_back(circle);
	}*/
}

//--------------------------------------------------------------
void TestApp::resized(int w, int h){
}

void TestApp::drawBackground()
{
	auto shader = backgroundShader;
	shader.begin();
	shader.setUniform1f("timeValX", ofGetElapsedTimef() * 0.1 );
	shader.setUniform1f("timeValY", -ofGetElapsedTimef() * 0.18 );
	
	//we also pass in the mouse position 
	//we have to transform the coords to what the shader is expecting which is 0,0 in the center and y axis flipped. 
	ofVec2f pos = player.circle.getPosition();
	shader.setUniform2f("centerPos", pos.x, ofGetWindowHeight() - pos.y - 1 );

	ofFill();
//	ofSetColor(245, 58, 135);
	int w = ofGetWidth();
	int h = ofGetHeight();
	ofRect(0, 0, w, h);
	
	shader.end();
}


void TestApp::setupLighting()
{
	ofVec2f playerPos = player.circle.getPosition();
	playerLight.setPosition(ofVec2f(playerPos.x,playerPos.y));
	playerLight.setDiffuseColor(ofFloatColor::white);
	
	playerLight.enable();
}




void Player::load(const string &url)
{
}

void Player::draw()
{
	ofFill();
	circle.draw();
}

void Player::setup(ofxBox2d* box2d, ofVec2f pos)
{
	circle.setPhysics(5, 1, 0.05); // s(3.0, 0.53, 0.05);
//		circle.setVelocity( (pos-clickPos) * 0.1f );
	circle.setup(box2d->getWorld(), pos, 15);
	
	SetBodyCollision(circle.body, COL_PLAYER, COL_ALL);
}


void Bullet::setup(ofxBox2d* box2d, ofVec2f pos, ofVec2f dir)
{
//	circle.setPhysics(3,0.5,0.01);
//	circle.setup(box2d->getWorld(), pos, radius);
//	circle.setVelocity( dir );

	float w=40;
	float h=40;

	ofPolyline pl = ofPolyline::fromRectangle(ofRectangle(-w/2, -h/2, w, h));

	auto v = pl.getVertices();
	for(int i=0;i<v.size();i++)
		shape.addVertex(v[i]);
	shape.close();
	shape.setAsEdge(false);
	shape.setPhysics(3,0.1,0.01);
	shape.create(box2d->getWorld());
	shape.setPosition(pos);
	shape.setVelocity(dir);
	shape.body->SetAngularVelocity(10);

	SetBodyCollision(shape.body, COL_BULLET, COL_ALL);
	
	startTime = ofGetElapsedTimef();
}

void TestApp::initFixedCircles()
{
	struct { int x,y; } pos[] = {
		{ 339, 594 },
		{ 246, 518 },
		{ 318, 512 },
		{ 363, 513 },
		{ 436, 517 },
		{ 540, 353 },
		{ 575, 471 },
		{ 153, 358 },
		{ 409, 344 },
		{ 403, 267 },
		{ 292, 268 },
		{ 349, 197 },
		{ 188, 213 },
		{ 194, 197 },
		{ 199, 181 },
		{ 205, 169 },
		{ 282, 347 }
	};
	 
	int nc = sizeof(pos)/(sizeof(typeof(pos[0])));
	for(int i=0;i<nc;i++) {
		addFixedCircle( ofVec2f(pos[i].x, pos[i].y ));
	}
}
